﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using lumo.display.object2D;
using lumo.display.animation2D;

namespace lumo.display.gui
{
    /// <summary>
    /// A custom command list.
    /// </summary>
    public class CustomCommandList : CommandListBase
    {
        /// <summary>
        /// Event Enumeration
        /// </summary>
        public enum Events
        {
            CheckItemAdded,
            GetBoundaries,
            Initialize,
            InitializeItem,
            Setup,
            SetupItem,
            Finalize,
            FinalizeItem,
            ChangeIndex,
            UnselectItem,
            SelectItem,
            Draw,
            Update
        }

        /// <summary>
        /// Custom command list arguments.
        /// </summary>
        public class CommandListEventArgs : EventArgs
        {
            public Events Type;
            public List<object> CommandList;
            public ParallelAnimation2D ParallelAnimation;
            public Dictionary<object, ParallelAnimation2D> ChangeAnimationDictionary;
            public ParallelAnimation2D ChangeAnimation;
            public object Item;
            public int ItemIndex;
            public float InitializeTime;
            public float FinalizeTime;
            public float ChangeIndexTime;
            public int LastIndex;
            public int Index;
            public Rectangle? Boundaries;
            public Microsoft.Xna.Framework.Graphics.SpriteBatch SpriteBatch;
        }

        /// <summary>
        /// Delegate function.
        /// </summary>
        /// <param name="Sender"></param>
        /// <param name="Args"></param>
        public delegate void CommandListEventHandler(object Sender, CommandListEventArgs Args);

        /// <summary>Space Between Each Item.</summary>
        public float ChangeTime = 500.0f;

        // Events
        public event CommandListEventHandler CheckItemAddedEvent;
        public event CommandListEventHandler GetBoundariesEvent;
        public event CommandListEventHandler InitializeEvent;
        public event CommandListEventHandler InitializeItemEvent;
        public event CommandListEventHandler SetupEvent;
        public event CommandListEventHandler SetupItemEvent;
        public event CommandListEventHandler FinalizeEvent;
        public event CommandListEventHandler FinalizeItemEvent;
        public event CommandListEventHandler SelectItemEvent;
        public event CommandListEventHandler UnselectItemEvent;
        public event CommandListEventHandler ChangeIndexEvent;
        public event CommandListEventHandler DrawEvent;
        public event CommandListEventHandler UpdateEvent;

        /// <summary></summary>
        private CommandListEventArgs _InternalArgs = new CommandListEventArgs();

        /// <summary>
        /// Check the item added.
        /// </summary>
        protected override void CheckItemAdded(object Item)
        {
            if (CheckItemAddedEvent != null)
            {
                _InternalArgs.Type = Events.CheckItemAdded;
                _InternalArgs.Item = Item;
                CheckItemAddedEvent(this, _InternalArgs);
            }
        }

        /// <summary>
        /// Get boundaries of an item
        /// </summary>
        protected override Rectangle? GetBoundaries(int Index)
        {
            if (GetBoundariesEvent != null)
            {
                _InternalArgs.Type = Events.GetBoundaries;
                _InternalArgs.Item = CommandList[Index];
                _InternalArgs.ItemIndex = Index;
                _InternalArgs.Boundaries = null;
                GetBoundariesEvent(this, _InternalArgs);
                return _InternalArgs.Boundaries;
            }
            return null;
        }

        /// <summary>
        /// Initialize the item.
        /// </summary>
        protected override void OnInitialize(float Time)
        {
            _InternalArgs.CommandList = CommandList;
            _InternalArgs.ParallelAnimation = ParallelAnimation;
            _InternalArgs.ChangeAnimationDictionary = ChangeAnimationDictionary;
            _InternalArgs.InitializeTime = Time;
            _InternalArgs.Index = this.Index;

            if (InitializeEvent != null)
            {
                _InternalArgs.Type = Events.Initialize;
                InitializeEvent(this, _InternalArgs);
            }

            if (InitializeItemEvent != null)
            {
                _InternalArgs.Type = Events.InitializeItem;
                int i = 0;
                foreach(object Item in CommandList)
                {
                    _InternalArgs.ChangeAnimation = ChangeAnimationDictionary[Item];
                    _InternalArgs.Item = Item;
                    _InternalArgs.ItemIndex = i++;
                    InitializeItemEvent(this, _InternalArgs);
                }
            }
        }

        /// <summary>
        /// Setup the item after initialize.
        /// </summary>
        protected override void OnSetup()
        {
            _InternalArgs.Index = this.Index;

            if (SetupEvent != null)
            {
                _InternalArgs.Type = Events.Setup;
                SetupEvent(this, _InternalArgs);
            }

            if (SetupItemEvent != null)
            {
                _InternalArgs.Type = Events.SetupItem;
                int i = 0;
                foreach(object Item in CommandList)
                {
                    _InternalArgs.ChangeAnimation = ChangeAnimationDictionary[Item];
                    _InternalArgs.Item = Item;
                    _InternalArgs.ItemIndex = i++;
                    SetupItemEvent(this, _InternalArgs);
                }
            }
        }

        /// <summary>
        /// Terminate the menu.
        /// </summary>
        protected override void OnTerminate(float Time)
        {
            _InternalArgs.Index = this.Index;
            _InternalArgs.FinalizeTime = Time;

            if (FinalizeEvent != null)
            {
                _InternalArgs.Type = Events.Finalize;
                FinalizeEvent(this, _InternalArgs);
            }

            if (FinalizeItemEvent != null)
            {
                _InternalArgs.Type = Events.FinalizeItem;
                int i = 0;
                foreach (object Item in CommandList)
                {
                    _InternalArgs.ChangeAnimation = ChangeAnimationDictionary[Item];
                    _InternalArgs.Item = Item;
                    _InternalArgs.ItemIndex = i++;
                    FinalizeItemEvent(this, _InternalArgs);
                }
            }
        }

        /// <summary>
        /// Unselect the item.
        /// </summary>
        protected override void OnUnselectItem(int ItemIndex, object Item)
        {
            if (UnselectItemEvent != null)
            {
                _InternalArgs.Type = Events.UnselectItem;
                _InternalArgs.ChangeAnimation = ChangeAnimationDictionary[Item];
                _InternalArgs.Item = Item;
                _InternalArgs.ItemIndex = ItemIndex;
                UnselectItemEvent(this, _InternalArgs);
            }
        }

        /// <summary>
        /// Select the item.
        /// </summary>
        protected override void OnSelectItem(int ItemIndex, object Item)
        {
            if (SelectItemEvent != null)
            {
                _InternalArgs.Type = Events.SelectItem;
                _InternalArgs.ChangeAnimation = ChangeAnimationDictionary[Item];
                _InternalArgs.Item = Item;
                _InternalArgs.ItemIndex = ItemIndex;
                SelectItemEvent(this, _InternalArgs);
            }
        }
        /// <summary>
        /// Select the item.
        /// </summary>
        protected override void OnChangeIndex(int LastIndex, int Index)
        {
            if (ChangeIndexEvent != null)
            {
                _InternalArgs.Type = Events.ChangeIndex;
                _InternalArgs.Index = Index;
                _InternalArgs.LastIndex = LastIndex;
                ChangeIndexEvent(this, _InternalArgs);
            }
        }

        /// <summary>
        /// Update the item.
        /// </summary>
        protected override void OnDraw(object Item, Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
        {
            if (DrawEvent != null)
            {
                _InternalArgs.Type = Events.Draw;
                _InternalArgs.Item = Item;
                _InternalArgs.SpriteBatch = spriteBatch;
                DrawEvent(this, _InternalArgs);
            }
        }

        /// <summary>
        /// Update the item.
        /// </summary>
        protected override void OnUpdate()
        {
            if (UpdateEvent != null)
            {
                _InternalArgs.Type = Events.Update;
                _InternalArgs.Index = this.Index;
                UpdateEvent(this, _InternalArgs);
            }
        }
    }
}
